#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
using namespace ns_log;
using task_t = std::function<void()>;
class Route
{
private:
    // 在线用户
    std::vector<InetAddr> _online;
    std::mutex _mtx;

public:
    Route()
    {
    }
    ~Route()
    {
    }
    // 添加用户模块
    void CheckOnlineUser(InetAddr &who)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        for (auto &user : _online)
        {
            if (user == who)
            {
                return;
            }
        }
        _online.push_back(who);
        LOG(INFO, "用户[%s][%d]已上线!\n", who.IP().c_str(), who.Port());
    }
    // 移除下线用户模块
    void DeleteOnlineUser(InetAddr &who)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        auto iter = _online.begin();
        while (iter != _online.end())
        {
            if (*iter == who)
            {
                _online.erase(iter);
                printf("用户[%s][%d]已下线!\n", who.IP().c_str(), who.Port());
                break;
            }
            ++iter;
        }
    }
    void ForWard(int sockfd, const std::string info, InetAddr& addr)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        // 转发信息--观察者模式
        std::string message = addr.GetInetAddrStr() + info;
        for (auto &user : _online)
        {
            struct sockaddr_in peer = user.GetAddr();
            // std::cout<<"message = "<<message<<"sockfd = "<<sockfd<<std::endl;
            ssize_t n = ::sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(peer), sizeof(peer));
            if (n < 0)
                LOG(ERROR, "send error!,address = %s\n", addr.GetInetAddrStr().c_str());
                std::cout<<strerror(errno)<<std::endl;
        }
    }
    void RouteHandler(int sockfd, const std::string &info, InetAddr &who)
    {
        CheckOnlineUser(who);
        task_t task;
        if (info == "Q" || info == "quit" || info == "q")
        {
            DeleteOnlineUser(who);
            std::string str = who.GetInetAddrStr();
            str += "已下线!\n";
            task = std::bind(&Route::ForWard, this, sockfd, str, who);
        }
        else
        {
            task = std::bind(&Route::ForWard, this, sockfd, info, who);
        }
        ThreadPool<task_t>::GetThreadPoolInstance()->Push(task);
    }
};